# To change this template, choose Tools | Templates
# and open the template in the editor.

from game.object.doodad import DoodadState
from game.object.character import NPCharacter
import os
import pygame
import random

import xml.etree.ElementTree as etree

from collections import OrderedDict


from game.level import *
from game.object.doodad import *
from game.object.armor import Armor
from game.object.weapon import Weapon
from game.object.character import *

class ResourceManager:
    def __init__(self, sprite_pitch):
        self.sprite_pitch = sprite_pitch
        self.loader = ["char", "weapon", "armor", "terrain", "doodad"]
        self.spriters = ["char", "weapon", "armor"]

        self.slots = OrderedDict([
            ("weapon",["main_hand","off_hand"]),
            ("armor",["head","body","arms","legs"]),
            ("access",["ring_l","ring_r","amulet"])
            ])
        self.attributes = ["hp", "mp", "en", "str", "spd", "dex", "end"]
        self.inv_grp = ["weapon", "armor", "accessory", "food"]


        self.xml_doc = {}
        self.sprite_sheet = {}
        for ltype in self.loader:
            self.xml_doc[ltype] = etree.parse("data/x_{0}.xml".format(ltype))
        for stype in self.spriters:
            self.sprite_sheet[stype] = self.load_image("sprite_{0}_{1}x{2}.png".format(stype, self.sprite_pitch[0], self.sprite_pitch[1]))



    def load_image(self, name):
        """
        Generic loader for an image from a file. The image is assumed to be an alpha model image
        such as a png, and resides in the data/sprites folder
        Returns a pygame Surface object of the image
        """
        fullname = os.path.join('data', 'sprites', name)
        try:
            image = pygame.image.load(fullname)
        except pygame.error, message:
            print 'Cannot load image:', name
            raise SystemExit, message
        image = image.convert_alpha()
        return image

    def load_subimage(self, image, x, y, w, h):
        """
        Helper method for the subsurface method by constructing the rect
        """
        rect = pygame.Rect(x, y, w, h)
        return image.subsurface(rect)

    def load_block(self, size, color, alpha=None):
        """
        Creates a solid block of color. The size is a dimension in the form (width, height) and the
        color is in the form (r, g, b) from 0-255 and the alpha is optional, also in 0(transparent)-255(opaque)
        """
        img = pygame.Surface(size)
        img = img.convert()
        img.fill(color)
        if alpha is not None:
            img.set_alpha(alpha)
        return img

    def load_tileset(self, lvl):
        d = self.sprite_pitch
        img = self.load_image('sprite_level_{0}_{1}x{2}.png'.format(lvl.theme, d[0], d[1]))

        #terrain types
        lvl.tileset['none'] = {"0":self.load_subimage(img,0,0,d[0],d[1])}
        lvl.tileset['room'] = {"0":self.load_subimage(img, d[0],0,d[0],d[1])}
        lvl.tileset['corridor'] = {"0":self.load_subimage(img, d[0],0,d[0],d[1])}

        #doodads
        lvl.tileset['door'] = {
            "closed":self.load_subimage(img, d[0]*3,0,d[0],d[1]),
            "open":  self.load_subimage(img, d[0]*4,0,d[0],d[1]),
            "locked":self.load_subimage(img, d[0]*3,0,d[0],d[1])}

        lvl.tileset['wall'] = {
            "north": self.load_subimage(img, 0,d[1],d[0],d[1]),
            "east": self.load_subimage(img, d[0],d[1],d[0],d[1]),
            "south": self.load_subimage(img, d[0]*2,d[1],d[0],d[1]),
            "west": self.load_subimage(img, d[0]*3,d[1],d[0],d[1]),
            "north_west":self.load_subimage(img, d[0]*4,d[1],d[0],d[1]),
            "north_east":self.load_subimage(img, d[0]*5,d[1],d[0],d[1]),
            "south_east":self.load_subimage(img, d[0]*6,d[1],d[0],d[1]),
            "south_west":self.load_subimage(img, d[0]*7,d[1],d[0],d[1])}

    #this is used to load the character from the data file. Not to be used for
    #loading save game data characters, they should call the load_char method
    def create_char(self, name):
        ch = Character(name)
        return self.create_char_(ch)

    def create_npchar(self, name):
        npc = NPCharacter(name)
        return self.create_char_(npc)

    def create_char_(self, ch):
        char_nodes = self.xml_doc['char'].getiterator('char')
        char_node = None
        for cn in char_nodes:
            if cn.get('name') == ch.name:
                char_node = cn
                break

        if char_node is None:
            raise NameError('Specified Character Not Found')

        #Do init stuff
        for a in self.attributes:
            ch.attribute[a] = CharAttribute()

        for ig in self.inv_grp:
            ch.inventory[ig] = []

        for k,v in self.slots.items():
            ch.equipment[k] = OrderedDict()
            for s in v:
                ch.equipment[k][s] = None


        #Do data loading here

        ch.subj_name = char_node.get('s_name', ch.name)
        ch.objv_name = char_node.get('o_name', ch.subj_name)
        ch.subj_plural = int(char_node.get('s_plural', 1))

        min_exp = int(char_node.get('min_exp', 0))
        max_exp = int(char_node.get('max_exp', min_exp))

        if min_exp == max_exp:
            ch.exp = min_exp
        else:
            ch.exp = random.randint(min_exp, max_exp)

        sprx, spry = int(char_node.get('sprx')) * self.sprite_pitch[0], int(char_node.get('spry')) * self.sprite_pitch[1]
        sprw, sprh = int(char_node.get('sprw',1)) * self.sprite_pitch[0], int(char_node.get('sprh',1)) * self.sprite_pitch[1]

        ch.rect = pygame.Rect(sprx, spry, sprw, sprh)

        ch.image = self.sprite_sheet['char'].subsurface(ch.rect)

        attrs_node = char_node.find('attr')
        if (attrs_node is not None):
            for k, v in ch.attribute.items():

                att_node = attrs_node.find(k)
                min = int(att_node.get('min', 0))
                max = int(att_node.get('max', min))
                if min == max:
                    v.tru = min
                else:
                    v.tru = random.randint(min, max)
                v.regen = int(att_node.get('regen', 0))
                v.dmg = 0

        equip_node = char_node.find('equip')
        if equip_node is not None:
            equips = equip_node.findall('item')
            for equip in equips:
                e_type = equip.get('type')
                e_slot = equip.get('slot')
                e_name = equip.get('name')
                ch.equipment[e_type][e_slot] = self.create_item(e_name, e_type)

        invent_node = char_node.find('invent')
        if invent_node is not None:
            invents = invent_node.findall('item')
            for invent in invents:
                e_type = invent.get('type')
                e_name = invent.get('name')
                ch.inventory[e_type].append(self.create_item(e_name, e_type))

        return ch

    def create_item(self, name, type):
        if type == 'weapon':
            return self.create_weapon(name)
        elif type == 'armor':
            return self.create_armor(name)
        else:
            return None

    def create_weapon(self, name):
        wp = Weapon(name)
        wep_nodes = self.xml_doc['weapon'].getiterator('wep')
        wep_node = None
        for wn in wep_nodes:
            if wn.get('name') == wp.name:
                wep_node = wn
                break

        if wep_node is None:
            raise NameError('Specified Weapon Not Found')

        wp.typ = wep_node.get('typ')
        wp.cat = wep_node.get('cat')
        wp.base_atk = wep_node.get('atk')
        wp.base_dmg_min = wep_node.get('dmg_min')
        wp.base_dmg_max = wep_node.get('dmg_max')

        sprx, spry = int(wep_node.get('sprx')) * self.sprite_pitch[0], int(wep_node.get('spry')) * self.sprite_pitch[1]
        sprw, sprh = int(wep_node.get('sprw',1)) * self.sprite_pitch[0], int(wep_node.get('sprh',1)) * self.sprite_pitch[1]

        wp.rect = pygame.Rect(sprx, spry, sprw, sprh)

        wp.image = self.sprite_sheet['weapon'].subsurface(wp.rect)

        return wp

    def create_armor(self, name):
        am = Armor(name)
        arm_nodes = self.xml_doc['armor'].getiterator('arm')
        arm_node = None
        for wn in arm_nodes:
            if wn.get('name') == am.name:
                arm_node = wn
                break

        if arm_node is None:
            raise NameError('Specified Armor Not Found: {0}'.format(name))

        am.typ = arm_node.get('typ')
        am.cat = arm_node.get('cat')
        am.base_def = arm_node.get('def_r')
        am.base_dt = arm_node.get('dmg_t')
        am.base_dr = arm_node.get('dmg_r')

        sprx, spry = int(arm_node.get('sprx')) * self.sprite_pitch[0], int(arm_node.get('spry')) * self.sprite_pitch[1]
        sprw, sprh = int(arm_node.get('sprw',1)) * self.sprite_pitch[0], int(arm_node.get('sprh',1)) * self.sprite_pitch[1]

        am.rect = pygame.Rect(sprx, spry, sprw, sprh)

        am.image = self.sprite_sheet['armor'].subsurface(am.rect)

        return am

    def load_doodad(self, name, state):
        dd = Doodad(name)
        dd_nodes = self.xml_doc['doodad'].getiterator('doodad')
        dd_node = None
        for dn in dd_nodes:
            if dn.get('name') == dd.name:
                dd_node = dn
                break

        if dd_node is None:
            raise NameError('Specified Doodad Not Found: {0}'.format(name))

        act_nodes = dd_node.getiterator('act')
        for an in act_nodes:
            dd.actions.append(an.text)

        return self.load_doodad_state(dd, state)

    def load_doodad_state(self, dd, state):
        dd_nodes = self.xml_doc['doodad'].getiterator('doodad')
        dd_node = None
        for dn in dd_nodes:
            if dn.get('name') == dd.name:
                dd_node = dn
                break

        if dd_node is None:
            raise NameError('Specified Doodad Not Found: {0}'.format(name))

        st_nodes = dd_node.getiterator('state')
        st_node = None
        for sn in st_nodes:
            if sn.get('name') == state:
                st_node = sn
                break

        if st_node is None:
            raise NameError('Specified State for Doodad Not Found: {0} {1}'.format(name, state))

        dd.state = DoodadState(state)
        dd.state.block_light = int(st_node.get('block_light', 1))
        dd.state.block_sound = int(st_node.get('block_sound', 1))
        dd.state.block_path = int(st_node.get('block_path', 1))
        dd.state.block_roof = int(st_node.get('block_roof', 1))
        dd.state.allow_diag = int(st_node.get('diag', 1))
        dd.state.act_default = st_node.get('act_def', None)

        act_nodes = st_node.getiterator('act')
        for an in act_nodes:
            dd.state.actions.append(an.text)

        return dd


    def load_terrain(self, name):
        ter = Terrain(name)
        ter_nodes = self.xml_doc['terrain'].getiterator('terrain')
        ter_node = None
        for tn in ter_nodes:
            if tn.get('name') == ter.name:
                ter_node = tn
                break

        if ter_node is None:
            raise NameError('Specified Terrain Not Found: {0}'.format(name))

        ter.block_light = int(ter_node.get('block_light', 1))
        ter.block_sound = int(ter_node.get('block_sound', 1))
        ter.block_path = int(ter_node.get('block_path', 1))
        ter.block_roof = int(ter_node.get('block_roof', 1))
        ter.move_penalty = int(ter_node.get('move_pen', 0))
        ter.ambient_light = int(ter_node.get('ambient', 0))
        ter.acoustics = int(ter_node.get('acoustic', 0))

        return ter


    def load_gui_icons(self, s):
        img = self.load_image('gui_{0}.png'.format(s))

        #terrain types
        gui = {
            'open_idle': self.load_subimage(img, 0, 0, s, s),
            'open_hover': self.load_subimage(img, 0, s, s, s),
            'close_idle': self.load_subimage(img, s, 0, s, s),
            'close_hover': self.load_subimage(img, s, s, s, s)
        }

        return gui